package cn.bellychang.queue.bobo.linkedqueue04addlastandremovefirst;

import cn.bellychang.iiterface.bobo.Queue;

/**
 * @author: bellychang
 * @date: 2020/2/12
 */
public class LinkedQueue<E> implements Queue<E> {

    private Node dummyHead;

    private Node tail;

    private int size;

    public LinkedQueue() {
        dummyHead = new Node(null);
        tail = dummyHead;
        size = 0;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        Node temp = dummyHead.next;
        while (temp != null) {
            builder.append(temp.value)
                    .append("->");
            temp = temp.next;
        }
        String s = builder.length() >= 2 ? builder.toString().substring(0, builder.length() - 2) : builder.toString();
        return String.format("LinkedQueue Head {%s} Tail", s);
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void enqueue(E e) {
        addLast(e);
    }

    @Override
    public E dequeue() {
        return removeFirst();
    }

    @Override
    public E getFront() {
        return getFirst();
    }

    private void addLast(E e) {
        Node newNode = new Node(e);
        if (isEmpty()) {
            dummyHead.next = tail;
        }
        tail.next = newNode;
        tail = newNode;
        size++;
    }

    private E removeFirst() {
        if (isEmpty()) {
            throw new IllegalArgumentException();
        }
        Node target = dummyHead.next;
        dummyHead.next = dummyHead.next.next;
        if (isEmpty()) {
            tail = dummyHead;
        }
        size--;
        target.next = null;
        return target.value;
    }

    private E getFirst() {
        if (isEmpty()) {
            throw new IllegalArgumentException();
        }
        return dummyHead.next.value;
    }

    private class Node {
        private E value;

        private Node next;

        public Node(E value) {
            this.value = value;
        }

        public Node(E value, Node next) {
            this.value = value;
            this.next = next;
        }

        @Override
        public String toString() {
            return value.toString();
        }
    }


}
